home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Reference Guide / C-C++ Interactive Reference Guide.iso / c_ref / csource5 / 365_01 / input.c < prev    next >
C/C++ Source or Header  |  1992-04-06  |  17KB  |  853 lines

  1. /* input.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the input() function, which implements vi's INPUT mode.
  12.  * It also contains the code that supports digraphs.
  13.  */
  14.  
  15. #include "config.h"
  16. #include "ctype.h"
  17. #include "vi.h"
  18.  
  19.  
  20. #ifndef NO_DIGRAPH
  21. static struct _DIG
  22. {
  23.     struct _DIG    *next;
  24.     char        key1;
  25.     char        key2;
  26.     char        dig;
  27.     char        save;
  28. } *digs;
  29.  
  30. char digraph(key1, key2)
  31.     char    key1;    /* the underlying character */
  32.     char    key2;    /* the second character */
  33. {
  34.     int        newkey;
  35.     REG struct _DIG    *dp;
  36.  
  37.     /* if digraphs are disabled, then just return the new char */
  38.     if (!*o_digraph)
  39.     {
  40.         return key2;
  41.     }
  42.  
  43.     /* remember the new key, so we can return it if this isn't a digraph */
  44.     newkey = key2;
  45.  
  46.     /* sort key1 and key2, so that their original order won't matter */
  47.     if (key1 > key2)
  48.     {
  49.         key2 = key1;
  50.         key1 = newkey;
  51.     }
  52.  
  53.     /* scan through the digraph chart */
  54.     for (dp = digs;
  55.          dp && (dp->key1 != key1 || dp->key2 != key2);
  56.          dp = dp->next)
  57.     {
  58.     }
  59.  
  60.     /* if this combination isn't in there, just use the new key */
  61.     if (!dp)
  62.     {
  63.         return newkey;
  64.     }
  65.  
  66.     /* else use the digraph key */
  67.     return dp->dig;
  68. }
  69.  
  70. /* this function lists or defines digraphs */
  71. void do_digraph(bang, extra)
  72.     int    bang;
  73.     char    extra[];
  74. {
  75.     int        dig;
  76.     REG struct _DIG    *dp;
  77.     struct _DIG    *prev;
  78.     static int    user_defined = FALSE; /* boolean: are all later digraphs user-defined? */
  79.     char        listbuf[8];
  80.  
  81.     /* if "extra" is NULL, then we've reached the end of the built-ins */
  82.     if (!extra)
  83.     {
  84.         user_defined = TRUE;
  85.         return;
  86.     }
  87.  
  88.     /* if no args, then display the existing digraphs */
  89.     if (*extra < ' ')
  90.     {
  91.         listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' ';
  92.         listbuf[7] = '\0';
  93.         for (dig = 0, dp = digs; dp; dp = dp->next)
  94.         {
  95.             if (dp->save || bang)
  96.             {
  97.                 dig += 7;
  98.                 if (dig >= COLS)
  99.                 {
  100.                     addch('\n');
  101.                     exrefresh();
  102.                     dig = 7;
  103.                 }
  104.                 listbuf[3] = dp->key1;
  105.                 listbuf[4] = dp->key2;
  106.                 listbuf[6] = dp->dig;
  107.                 qaddstr(listbuf);
  108.             }
  109.         }
  110.         addch('\n');
  111.         exrefresh();
  112.         return;
  113.     }
  114.  
  115.     /* make sure we have at least two characters */
  116.     if (!extra[1])
  117.     {
  118.         msg("Digraphs must be composed of two characters");
  119.         return;
  120.     }
  121.  
  122.     /* sort key1 and key2, so that their original order won't matter */
  123.     if (extra[0] > extra[1])
  124.     {
  125.         dig = extra[0];
  126.         extra[0] = extra[1];
  127.         extra[1] = dig;
  128.     }
  129.  
  130.     /* locate the new digraph character */
  131.     for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++)
  132.     {
  133.     }
  134.     dig = extra[dig];
  135.     if (!bang && dig)
  136.     {
  137.         dig |= 0x80;
  138.     }
  139.  
  140.     /* search for the digraph */
  141.     for (prev = (struct _DIG *)0, dp = digs;
  142.          dp && (dp->key1 != extra[0] || dp->key2 != extra[1]);
  143.          prev = dp, dp = dp->next)
  144.     {
  145.     }
  146.  
  147.     /* deleting the digraph? */
  148.     if (!dig)
  149.     {
  150.         if (!dp)
  151.         {
  152. #ifndef CRUNCH
  153.             msg("%c%c not a digraph", extra[0], extra[1]);
  154. #endif
  155.             return;
  156.         }
  157.         if (prev)
  158.             prev->next = dp->next;
  159.         else
  160.             digs = dp->next;
  161.         free(dp);
  162.         return;
  163.     }
  164.  
  165.     /* if necessary, create a new digraph struct for the new digraph */
  166.     if (dig && !dp)
  167.     {
  168.         dp = (struct _DIG *)malloc(sizeof *dp);
  169.         if (!dp)
  170.         {
  171.             msg("Out of space in the digraph table");
  172.             return;
  173.         }
  174.         if (prev)
  175.             prev->next = dp;
  176.         else
  177.             digs = dp;
  178.         dp->next = (struct _DIG *)0;
  179.     }
  180.  
  181.     /* assign it the new digraph value */
  182.     dp->key1 = extra[0];
  183.     dp->key2 = extra[1];
  184.     dp->dig = dig;
  185.     dp->save = user_defined;
  186. }
  187.  
  188. # ifndef NO_MKEXRC
  189. void savedigs(fd)
  190.     int        fd;
  191. {
  192.     static char    buf[] = "digraph! XX Y\n";
  193.     REG struct _DIG    *dp;
  194.  
  195.     for (dp = digs; dp; dp = dp->next)
  196.     {
  197.         if (dp->save)
  198.         {
  199.             buf[9] = dp->key1;
  200.             buf[10] = dp->key2;
  201.             buf[12] = dp->dig;
  202.             write(fd, buf, (unsigned)14);
  203.         }
  204.     }
  205. }
  206. # endif
  207. #endif
  208.  
  209.  
  210. /* This function allows the user to replace an existing (possibly zero-length)
  211.  * chunk of text with typed-in text.  It returns the MARK of the last character
  212.  * that the user typed in.
  213.  */
  214. MARK input(from, to, when, above)
  215.     MARK    from;    /* where to start inserting text */
  216.     MARK    to;    /* extent of text to delete */
  217.     int    when;    /* either WHEN_VIINP or WHEN_VIREP */
  218.     int    above;    /* boolean: take indentation from lower line? */
  219. {
  220.     char    key[2];    /* key char followed by '\0' char */
  221.     char    *build;    /* used in building a newline+indent string */
  222.     char    *scan;    /* used while looking at the indent chars of a line */
  223.     MARK    m;    /* some place in the text */
  224. #ifndef NO_EXTENSIONS
  225.     int    quit = FALSE;    /* boolean: are we exiting after this? */
  226.     int    inchg;    /* boolean: have we done a "beforedo()" yet? */
  227. #endif
  228.  
  229. #ifdef DEBUG
  230.     /* if "from" and "to" are reversed, complain */
  231.     if (from > to)
  232.     {
  233.         msg("ERROR: input(%ld:%d, %ld:%d)",
  234.             markline(from), markidx(from),
  235.             markline(to), markidx(to));
  236.         return MARK_UNSET;
  237.     }
  238. #endif
  239.  
  240.     key[1] = 0;
  241.  
  242.     /* if we're replacing text with new text, save the old stuff */
  243.     /* (Alas, there is no easy way to save text for replace mode) */
  244.     if (from != to)
  245.     {
  246.         cut(from, to);
  247.     }
  248.  
  249.     /* if doing a dot command, then reuse the previous text */
  250.     if (doingdot)
  251.     {
  252.         ChangeText
  253.         {
  254.             /* delete the text that's there now */
  255.             if (from != to)
  256.             {
  257.                 delete(from, to);
  258.             }
  259.  
  260.             /* insert the previous text */
  261.             cutname('.');
  262.             cursor = paste(from, FALSE, TRUE) + 1L;
  263.         }
  264.     }
  265.     else /* interactive version */
  266.     {
  267.         /* assume that whoever called this already did a beforedo() */
  268. #ifndef NO_EXTENSIONS
  269.         inchg = TRUE;
  270. #endif
  271.  
  272.         /* if doing a change within the line... */
  273.         if (from != to && markline(from) == markline(to))
  274.         {
  275.             /* mark the end of the text with a "$" */
  276.             change(to - 1, to, "$");
  277.         }
  278.         else
  279.         {
  280.             /* delete the old text right off */
  281.             if (from != to)
  282.             {
  283.                 delete(from, to);
  284.             }
  285.             to = from;
  286.         }
  287.  
  288.         /* handle autoindent of the first line, maybe */
  289.         cursor = from;
  290.         m = (above ? (cursor + BLKSIZE) : (cursor - BLKSIZE));
  291.         if (*o_autoindent && markidx(m) == 0
  292.          && markline(m) >= 1L && markline(m) <= nlines)
  293.         {
  294.             /* Only autoindent blank lines. */
  295.             pfetch(markline(cursor));
  296.             if (plen == 0)
  297.             {
  298.                 /* Okay, we really want to autoindent */
  299.                 pfetch(markline(m));
  300.                 for (scan = ptext, build = tmpblk.c;
  301.                      *scan == ' ' || *scan == '\t';
  302.                      )
  303.                 {
  304.                     *build++ = *scan++;
  305.                 }
  306.                 if (build > tmpblk.c)
  307.                 {
  308.                     *build = '\0';
  309.                     add(cursor, tmpblk.c);
  310.                     cursor += (build - tmpblk.c);
  311.                     if (cursor > to)
  312.                         to = cursor;
  313.                 }
  314.             }
  315.         }
  316.  
  317.         /* repeatedly add characters from the user */
  318.         for (;;)
  319.         {
  320.             /* Get a character */
  321.             redraw(cursor, TRUE);
  322. #ifdef DEBUG2
  323.             msg("cursor=%ld.%d, to=%ld.%d",
  324.                 markline(cursor), markidx(cursor),
  325.                 markline(to), markidx(to));
  326. #endif
  327. #ifndef NO_ABBR
  328.             pfetch(markline(cursor));
  329.             build = ptext;
  330.             if (pline == markline(from))
  331.                 build += markidx(from);
  332.             for (scan = ptext + markidx(cursor); --scan >= build && isalnum(*scan); )
  333.             {
  334.             }
  335.             scan++;
  336.             key[0] = getabkey(when, scan, (int)(ptext + markidx(cursor) - scan));
  337. #else
  338.             key[0] = getkey(when);
  339. #endif
  340. #ifndef NO_VISIBLE
  341.             if (key[0] != '\0' && V_from != MARK_UNSET)
  342.             {
  343.                 msg("Can't modify text during a selection");
  344.                 beep();
  345.                 continue;
  346.             }
  347. #endif
  348.  
  349. #ifndef NO_EXTENSIONS
  350.             if (key[0] == ctrl('O'))
  351.             {
  352.                 if (inchg)
  353.                 {
  354.                     if (cursor < to)
  355.                     {
  356.                         delete(cursor, to);
  357.                         redraw(cursor, TRUE);
  358.                     }
  359.                     afterdo();
  360.                     inchg = FALSE;
  361.                 }
  362.             }
  363.             else if (key[0] != ctrl('['))
  364.             {
  365.                 if (!inchg)
  366.                 {
  367.                     beforedo(FALSE);
  368.                     inchg = TRUE;
  369.                 }
  370.             }
  371. #endif
  372.  
  373. #ifndef CRUNCH
  374.             /* if wrapmargin is set & we're past the
  375.              * warpmargin, then change the last whitespace
  376.              * characters on line into a newline
  377.              */
  378.             if (*o_wrapmargin != 0)
  379.             {
  380.                 pfetch(markline(cursor));
  381.                 if (idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff))
  382.                 {
  383.                     build = tmpblk.c;
  384.                     *build++ = '\n';
  385.                     if (*o_autoindent)
  386.                     {
  387.                         /* figure out indent for next line */
  388.                         for (scan = ptext; *scan == ' ' || *scan == '\t'; )
  389.                         {
  390.                             *build++ = *scan++;
  391.                         }
  392.                     }
  393.                     *build = '\0';
  394.  
  395.                     scan = ptext + plen;
  396.                     m = cursor & ~(BLKSIZE - 1);
  397.                     while (ptext < scan)
  398.                     {
  399.                         scan--;
  400.                         if (*scan != ' ' && *scan != '\t')
  401.                             continue;
  402.  
  403.                         /*break up line, and we do autoindent if needed*/
  404.                         change(m + (scan - ptext), m + (scan - ptext) + 1, tmpblk.c);
  405.                         cursor = (cursor & ~(BLKSIZE - 1))
  406.                             + BLKSIZE
  407.                             + strlen(tmpblk.c) - 1
  408.                             + plen - (scan - ptext) - 1;
  409.  
  410.                         /*remove trailing spaces on previous line*/
  411.                         pfetch(markline(m));
  412.                         scan = ptext + plen;
  413.                         while (ptext < scan)
  414.                         {
  415.                             scan--;
  416.                             if (*scan != ' ' && *scan != '\t')
  417.                                 break;
  418.                         }
  419.                         delete(m + (scan-ptext) + 1, m + plen);
  420.  
  421.                         break;
  422.                     }
  423.                 }
  424.             }
  425. #endif /* !CRUNCH */
  426.  
  427.             /* process it */
  428.             switch (*key)
  429.             {
  430. #ifndef NO_EXTENSIONS
  431.               case ctrl('O'): /* special movement mapped keys */
  432.                 *key = getkey(0);
  433.                 switch (*key)
  434.                 {
  435.                   case 'h':    m = m_left(cursor, 0L);        break;
  436.                   case 'j':
  437.                   case 'k':    m = m_updnto(cursor, 0L, *key);    break;
  438.                   case 'l':    m = cursor + 1;            break;
  439.                   case 'B':
  440.                   case 'b':    m = m_bword(cursor, 0L, *key);    break;
  441.                   case 'W':
  442.                   case 'w':    m = m_fword(cursor, 0L, *key, '\0');    break;
  443.                   case '^':    m = m_front(cursor, 0L);    break;
  444.                   case '$':    m = m_rear(cursor, 0L);        break;
  445.                   case ctrl('B'):
  446.                   case ctrl('F'):
  447.                         m = m_scroll(cursor, 0L, *key); break;
  448.                   case 'x':
  449. #ifndef NO_VISIBLE
  450.                         if (V_from)
  451.                             beep();
  452.                         else
  453. #endif
  454.                         ChangeText
  455.                         {
  456.                             m = v_xchar(cursor, 0L, 'x');
  457.                         }
  458.                         break;
  459.                   case 'i':    m = to = from = cursor;
  460.                         when = WHEN_VIINP + WHEN_VIREP - when;
  461.                                         break;
  462.                   case 'K':
  463.                     pfetch(markline(cursor));
  464.                     changes++; /* <- after this, we can alter ptext */
  465.                     ptext[markidx(cursor)] = 0;
  466.                     for (scan = ptext + markidx(cursor) - 1;
  467.                          scan >= ptext && isalnum(*scan);
  468.                          scan--)
  469.                     {
  470.                     }
  471.                     scan++;
  472.                     m = (*scan ? v_keyword(scan, cursor, 0L) : cursor);
  473.                     break;
  474.  
  475. # ifndef NO_VISIBLE
  476.                   case 'v':
  477.                   case 'V':
  478.                     if (V_from)
  479.                         V_from = MARK_UNSET;
  480.                     else
  481.                         V_from = cursor;
  482.                     m = from = to = cursor;
  483.                     V_linemd = (*key == 'V');
  484.                     break;
  485.  
  486.                   case 'd':
  487.                   case 'y':
  488.                   case '\\':
  489.                     /* do nothing if unmarked */
  490.                     if (!V_from)
  491.                     {
  492.                         msg("You must mark the text first");
  493.                         beep();
  494.                         break;
  495.                     }
  496.  
  497.                     /* "from" must come before "to" */
  498.                     if (V_from < cursor)
  499.                     {
  500.                         from = V_from;
  501.                         to = cursor;
  502.                     }
  503.                     else
  504.                     {
  505.                         from = cursor;
  506.                         to = V_from;
  507.                     }
  508.  
  509.                     /* we don't need V_from anymore */
  510.                     V_from = MARK_UNSET;
  511.  
  512.                     if (V_linemd)
  513.                     {
  514.                         /* adjust for line mode */
  515.                         from &= ~(BLKSIZE - 1);
  516.                         to |= (BLKSIZE - 1);
  517.                     }
  518.                     else
  519.                     {
  520.                         /* in character mode, we must
  521.                          * worry about deleting the newline
  522.                          * at the end of the last line
  523.                          */
  524.                         pfetch(markline(to));
  525.                         if (markidx(to) == plen)
  526.                             to |= (BLKSIZE - 1);
  527.                     }
  528.                     to++;
  529.  
  530.                     switch (*key)
  531.                     {
  532.                       case 'y':
  533.                         cut(from, to);
  534.                         break;
  535.  
  536.                       case 'd':
  537.                         ChangeText
  538.                         {
  539.                             cut(from, to);
  540.                             delete(from, to);
  541.                         }
  542.                         cursor = from;
  543.                         break;
  544.  
  545. #ifndef NO_POPUP
  546.                       case '\\':
  547.                         ChangeText
  548.                         {
  549.                             cursor = v_popup(from, to);
  550.                         }
  551.                         break;
  552. #endif
  553.                     }
  554.                     m = from = to = cursor;
  555.                     break;
  556.  
  557.                   case 'p':
  558.                   case 'P':
  559.                     V_from = MARK_UNSET;
  560.                     ChangeText
  561.                     {
  562.                         m = from = to = cursor = paste(cursor, (*key == 'p'), FALSE);
  563.                     }
  564.                     break;
  565. # endif /* !NO_VISIBLE */
  566.                   default:    m = MARK_UNSET;
  567.                 }
  568.  
  569.                 /* adjust the moved cursor */
  570.                 if (m != cursor)
  571.                 {
  572.                     m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? 0x20 : 0));
  573.                     if (*key == '$' || (*key == 'l' && m <= cursor))
  574.                     {
  575.                         m++;
  576.                     }
  577.                 }
  578.  
  579.                 /* if the cursor is reasonable, use it */
  580.                 if (m == MARK_UNSET)
  581.                 {
  582.                     beep();
  583.                 }
  584.                 else
  585.                 {
  586.                     from = to = cursor = m;
  587.                 }
  588.                 break;
  589.  
  590.               case ctrl('Z'):
  591.                 if (getkey(0) == ctrl('Z'))
  592.                 {
  593.                     quit = TRUE;
  594.                     goto BreakBreak;
  595.                 }
  596.                 break;
  597. #endif
  598.  
  599.               case ctrl('['):
  600.                 /* if last line contains only whitespace, then remove whitespace */
  601.                 if (*o_autoindent)
  602.                 {
  603.                     pfetch(markline(cursor));
  604.                     for (scan = ptext; isspace(*scan); scan++)
  605.                     {
  606.                     }
  607.                     if (scan > ptext && !*scan)
  608.                     {
  609.                         cursor &= ~(BLKSIZE - 1L);
  610.                         if (to < cursor + plen)
  611.                         {
  612.                             to = cursor + plen;
  613.                         }
  614.                     }
  615.                 }
  616.                 goto BreakBreak;
  617.  
  618.               case ctrl('U'):
  619.                 if (markline(cursor) == markline(from))
  620.                 {
  621.                     cursor = from;
  622.                 }
  623.                 else
  624.                 {
  625.                     cursor &= ~(BLKSIZE - 1);
  626.                 }
  627.                 break;
  628.  
  629.               case ctrl('D'):
  630.               case ctrl('T'):
  631.                 if (to > cursor)
  632.                 {
  633.                     delete(cursor, to);
  634.                 }
  635.                 mark[27] = cursor;
  636.                 cmd_shift(cursor, cursor, *key == ctrl('D') ? CMD_SHIFTL : CMD_SHIFTR, TRUE, "");
  637.                 if (mark[27])
  638.                 {
  639.                     cursor = mark[27];
  640.                 }
  641.                 else
  642.                 {
  643.                     cursor = m_front(cursor, 0L);
  644.                 }
  645.                 to = cursor;
  646.                 break;
  647.  
  648.               case '\b':
  649.                 if (cursor <= from)
  650.                 {
  651.                     beep();
  652.                 }
  653.                 else if (markidx(cursor) == 0)
  654.                 {
  655.                     cursor -= BLKSIZE;
  656.                     pfetch(markline(cursor));
  657.                     cursor += plen;
  658.                 }
  659.                 else
  660.                 {
  661.                     cursor--;
  662.                 }
  663.                 break;
  664.  
  665.               case ctrl('W'):
  666.                 m = m_bword(cursor, 1L, 'b');
  667.                 if (markline(m) == markline(cursor) && m >= from)
  668.                 {
  669.                     cursor = m;
  670.                     if (from > cursor)
  671.                     {
  672.                         from = cursor;
  673.                     }
  674.                 }
  675.                 else
  676.                 {
  677.                     beep();
  678.                 }
  679.                 break;
  680.  
  681.               case '\n':
  682. #if OSK
  683.               case '\l':
  684. #else                  
  685.               case '\r':
  686. #endif
  687.                 build = tmpblk.c;
  688.                 *build++ = '\n';
  689.                 if (*o_autoindent)
  690.                 {
  691.                     /* figure out indent for next line */
  692.                     pfetch(markline(cursor));
  693.                     for (scan = ptext; *scan == ' ' || *scan == '\t'; )
  694.                     {
  695.                         *build++ = *scan++;
  696.                     }
  697.  
  698.                     /* remove indent from this line, if blank */
  699.                     if ((scan - ptext) >= markidx(cursor) && plen > 0)
  700.                     {
  701.                         to = cursor &= ~(BLKSIZE - 1);
  702.                         delete(cursor, cursor + plen);
  703.                     }
  704.                 }
  705.                 *build = 0;
  706.                 if (cursor >= to && when != WHEN_VIREP)
  707.                 {
  708.                     add(cursor, tmpblk.c);
  709.                 }
  710.                 else
  711.                 {
  712.                     change(cursor, to, tmpblk.c);
  713.                 }
  714.                 redraw(cursor, TRUE);
  715.                 to = cursor = (cursor & ~(BLKSIZE - 1))
  716.                         + BLKSIZE
  717.                         + (int)(build - tmpblk.c) - 1;
  718.                 break;
  719.  
  720.               case ctrl('A'):
  721.               case ctrl('P'):
  722.                 if (cursor < to)
  723.                 {
  724.                     delete(cursor, to);
  725.                 }
  726.                 if (*key == ctrl('A'))
  727.                 {
  728.                     cutname('.');
  729.                 }
  730.                 to = cursor = paste(cursor, FALSE, TRUE) + 1L;
  731.                 break;
  732.  
  733.               case ctrl('V'):
  734.                 if (cursor >= to && when != WHEN_VIREP)
  735.                 {
  736.                     add(cursor, "^");
  737.                 }
  738.                 else
  739.                 {
  740.                     change(cursor, to, "^");
  741.                     to = cursor + 1;
  742.                 }
  743.                 redraw(cursor, TRUE);
  744.                 *key = getkey(0);
  745.                 if (*key == '\n')
  746.                 {
  747.                     /* '\n' too hard to handle */
  748. #if OSK
  749.                     *key = '\l';
  750. #else
  751.                     *key = '\r';
  752. #endif
  753.                 }
  754.                 change(cursor, cursor + 1, key);
  755.                 cursor++;
  756.                 if (cursor > to)
  757.                 {
  758.                     to = cursor;
  759.                 }
  760.                 break;
  761.  
  762.               case ctrl('L'):
  763.               case ctrl('R'):
  764.                 redraw(MARK_UNSET, FALSE);
  765.                 break;
  766.  
  767.               default:
  768.                 if (cursor >= to && when != WHEN_VIREP)
  769.                 {
  770.                     add(cursor, key);
  771.                     cursor++;
  772.                     to = cursor;
  773.                 }
  774.                 else
  775.                 {
  776.                     pfetch(markline(cursor));
  777.                     if (markidx(cursor) == plen)
  778.                     {
  779.                         add(cursor, key);
  780.                     }
  781.                     else
  782.                     {
  783. #ifndef NO_DIGRAPH
  784.                         *key = digraph(ptext[markidx(cursor)], *key);
  785. #endif
  786.                         change(cursor, cursor + 1, key);
  787.                     }
  788.                     cursor++;
  789.                 }
  790. #ifndef NO_SHOWMATCH
  791.                 /* show matching "({[" if necessary */
  792.                 if (*o_showmatch && strchr(")}]", *key))
  793.                 {
  794.                     redraw(cursor, TRUE);
  795.                     m = m_match(cursor - 1, 0L);
  796.                     if (markline(m) >= topline
  797.                      && markline(m) <= botline)
  798.                     {
  799.                         redraw(m, TRUE);
  800.                         refresh();
  801.                         sleep(1);
  802.                     }
  803.                 }
  804. #endif
  805.             } /* end switch(*key) */
  806.         } /* end for(;;) */
  807. BreakBreak:;
  808.         /* delete any excess characters */
  809.         if (cursor < to)
  810.         {
  811. #ifndef NO_EXTENSIONS
  812.             /* if we aren't in the middle of a change, start one! */
  813.             if (!inchg)
  814.             {
  815.                 beforedo(FALSE);
  816.                 inchg = TRUE;
  817.             }
  818. #endif
  819.             delete(cursor, to);
  820.         }
  821.  
  822.     } /* end if doingdot else */
  823.  
  824.     /* put the new text into a cut buffer for possible reuse */
  825.     if (!doingdot)
  826.     {
  827.         blksync();
  828.         cutname('.');
  829.         cut(from, cursor);
  830.     }
  831.  
  832.     /* move to last char that we inputted, unless it was newline */
  833.     if (markidx(cursor) != 0)
  834.     {
  835.         cursor--;
  836.     }
  837.     redraw(cursor, FALSE);
  838.  
  839. #ifndef NO_EXTENSIONS
  840.     if (quit)
  841.     {
  842.         /* if this is a nested "do", then cut it short */
  843.         abortdo();
  844.  
  845.         /* exit, unless we can't write out the file */
  846.         cursor = v_xit(cursor, 0L, 'Z');
  847.     }
  848. #endif
  849.  
  850.     rptlines = 0L;
  851.     return cursor;
  852. }
  853.